<template>
  <div>
    <div
      style="display: flex; margin-bottom: 10px"
      :style="{ justifyContent: showFilter ? 'space-between' : 'flex-end' }">
      <dt-filter v-if="showFilter" v-model="filterInfo" :items="filterItems" ref="filter" @filter="search" />
      <slot name="btn"></slot>
    </div>

    <div ref="table" style="position: relative">
      <ux-grid
        v-if="headerColumn"
        ref="head"
        :height="headerHeight"
        show-header-overflow="tooltip"
        style="overflow: hidden" />

      <ux-grid
        ref="grid"
        widthResize
        :size="size"
        rowKey
        :border="border"
        :span-method="select ? select.spanMethod : null"
        :merge-cells="mergeCells"
        :highlight-current-row="highlightCurrentRow"
        show-overflow="tooltip"
        :show-header="!headerColumn"
        :cell-style="{ height: cellHeight ? cellHeight + 'px' : '' }"
        columnKey
        :height="heightResize ? '' : fixedHeight"
        :empty-text="emptyText"
        :edit-config="{ trigger: 'click', mode: 'row' }"
        :row-style="rowStyle"
        :checkboxConfig="select ? select.checkbox : null"
        @sort-change="onSortChange"
        @select-all="onSelectAll"
        @select="onSelectOne"
        @selection-change="onSelectChange"
        @table-body-scroll="onScroll" />

      <Spin fix v-show="loading">
        <Icon type="ios-loading" size="20" class="dt-loading"></Icon>
        <div>Loading</div>
      </Spin>
    </div>
    <dt-page v-if="page" v-model="pageOpt" @change="onPageChange" :showPageTotal="showPageTotal" />
  </div>
</template>

<script>
  import render from './render.js'
  import textMgr from '../info/text.js'
  import dtInfo from '@/components/dt/info'

  export default {
    props: {
      columnInfo: Array, // 兼容iview table
      columns: Array, // 原 umy-ui 加自定义render扩展
      list: Array,
      cellHeight: [Number, String],
      rowStyle: [Function, Object],
      height: [Number, String],
      heightResize: {
        type: Boolean,
        default: false
      },
      rowKey: Boolean,
      size: String,
      tree: Object,
      select: Object,
      mergeCells: Array,
      emptyText: String,
      page: [Object, Boolean],
      onFetch: Function,
      showPageTotal: {
        type: Boolean,
        default: true
      },
      highlightCurrentRow: {
        type: Boolean,
        default: true
      },
      scrollDefault: {
        type: Boolean,
        default: true
      },
      border: {
        type: Boolean,
        default: true
      }
    },
    watch: {
      columns(n) {
        this.handleOption()
      },
      columnInfo(n) {
        this.handleIview()
      },
      list(n) {
        this.loadList(n ?? [])
      },
      page: {
        handler(n) {
          if (typeof n == 'object') {
            this.pageOpt = { ...this.defaultPage, ...n }
          } else if (this.page) {
            this.pageOpt = this.defaultPage
          }
        },
        deep: true
      }
    },
    data() {
      return {
        fixedHeight: 500,
        scrollTop: '',
        vm: null,
        loading: false,
        showFilter: false,
        searchInfo: {},
        filterInfo: {},
        sortInfo: {},
        pageOpt: null,
        textItems: [],
        filterItems: [],

        // 多表头情况用2个表格实现虚拟渲染
        headerHeight: 0,
        headerColumn: null,

        currentList: null,
        defaultPage: {
          total: 0,
          current: 1,
          rows: 50,
          options: [10, 20, 30, 40, 50]
        },
        sortData: {} //需要排序的表头
      }
    },
    methods: {
      fixHeight() {
        if (this.height) {
          this.fixedHeight = this.height
        } else if (!this.heightResize) {
          setTimeout(() => {
            this.fixedHeight = Math.max(
              window.innerHeight - this.$dt.tool.getPositionTop(this.$refs.table) - 80 - this.headerHeight,
              200
            )
          }, 200)
        }
      },
      handleTxt(item) {
        if (item.field.indexOf('_txt_') < 0) {
          item.field = '_txt_' + item.field
        }
        return item
      },
      handleColumn(item) {
        if (!item.slots) {
          item.slots = {}
        }
        if (!item.slots.default && !item.cell && item.type != 'checkbox' && item.type != 'index') {
          item.cell = { text: {} }
        }
        if (item.treeNode && !this.tree) {
          item.treeNode = false
        }
        if (item.cell) {
          if (
            item.cell.text &&
            !textMgr.hasStyle(item.cell.text) &&
            item.field &&
            (!item.treeNode || !this.tree)
          ) {
            this.textItems.push(this.handleTxt(item))
          } else {
            item.slots.default = ({ row }, h) => {
              let opt = typeof item.cell == 'function' ? item.cell(row) : item.cell
              if (opt.text) {
                opt.text.max = (item.minWidth || item.width || 0) / 18.75
              }
              return render.option(this.vm, opt, item.field, row, h)
            }
          }
        }
        if (item.treeNode && this.tree) {
          item._tree = true
          item.treeNode = false
          let def = item.slots.default
          item.slots.default = ({ row }, h) => {
            let ren = def({ row }, h)
            return render.cell.tree(h, row, ren, this.tree, (row) => {
              this.getTreeRow(row)._tree_expand = row._tree_expand
              if (row._tree_expand) {
                this.insetTree(row)
              } else {
                this.removeTree(row)
              }
            })
          }
        }
        if ((item.header && item.visible != false) || (item.header && item.visibleSearch == true)) {
          if (item.header.filter) {
            this.showFilter = true
            this.filterItems.push(item.header.filter)
          }
          item.slots.header = ({ row }, h) => {
            let opt = typeof item.header == 'function' ? item.header(row) : item.header
            return render.option(this, opt, item.field, row, h)
          }
        }
        if (item.remoteSort) {
          this.sortData[item.field] = item.sort
        }
        if (item.children) {
          item.visible = item.children.some((itm) => itm.visible != false)
          item.children.map((i) => this.handleColumn(i))
        }
        return item
      },
      handleOption(opts = this.columns) {
        if (opts) {
          this.textItems = [] // 使用默认 text， 不使用 dt-info-edit-text
          this.filterItems = []
          let tableColumn = opts.map((i) => this.handleColumn(i))

          // if (tableColumn.some(i => i.children && i.children.length > 0)) {
          //   this.headerColumn = tableColumn
          //   let tmp = []
          //   tableColumn.forEach(item => {
          //     if (item.children) {
          //       item.children.forEach(i => tmp.push(i))
          //     } else {
          //       tmp.push(item)
          //     }
          //   })
          //   tableColumn = tmp
          //   setTimeout(() => {
          //     this.headerHeight = this.$refs.head.$children[0].$children[0].headerHeight
          //   })
          // } else {
          //   this.headerColumn = null
          // }
          if (this.currentList) {
            this.handleList(this.currentList)
            this.handleList(this.$refs.grid.getRecordset()) // 临时数据
          }
          this.$nextTick(() => {
            this.$refs.grid.reloadColumn(tableColumn)
            this.$refs.head?.reloadColumn(this.headerColumn)
            this.$refs.filter?.init()
          })
        }
      },
      // 兼容iview
      handleIviewOpt(opt) {
        opt.field = opt.key
        opt.slots = {}
        if (opt.render) {
          opt.slots.default = (params, h) => {
            return [opt.render(h, params)]
          }
        }
        if (opt.renderHeader) {
          opt.slots.header = (params, h) => {
            return [opt.renderHeader(h, params)]
          }
        }
        if (opt.children) {
          opt.children.forEach((item) => {
            this.handleIviewOpt(item)
          })
        }
        return opt
      },
      handleIview() {
        if (this.columnInfo) {
          this.handleOption(
            this.columnInfo.map((item) => {
              return this.handleIviewOpt(item)
            })
          )
        }
      },

      onSortChange(sort) {
        if (this.select && this.select.sort) {
          this.select.sort(sort)
        } else {
          let sortObj = this.sortData[sort.prop]
          if (sortObj) {
            this.sortInfo = {}
            this.sortInfo[sortObj.key] =
              sort.order == 'desc' ? sortObj.desc : sort.order == 'asc' ? sortObj.asc : ''
            this.fetch()
          }
        }
      },
      onSelectAll(selection) {
        if (this.select && this.select.all) {
          this.select.all(selection)
        }
      },
      onSelectOne(selection, row) {
        if (this.select && this.select.one) {
          this.select.one(selection, row)
        }
      },
      onSelectChange(selection) {
        if (this.select && this.select.change) {
          this.select.change(selection)
        }
      },
      onClearSelection() {
        this.$refs.grid.clearSelection()
      },
      init(vm, opt, filterInfo) {
        this.vm = vm
        if (filterInfo) {
          this.filterInfo = filterInfo
        }
        if (opt) {
          this.handleOption(opt.options())
        }
        this.clearSort()
      },
      update(opt) {
        this.handleOption(opt.options())
      },
      throwFilter() {
        return this.$refs.filter
      },
      clearFilter() {
        this.filterInfo = {}
        this.$nextTick(function () {
          this.$refs.filter && this.$refs.filter.clear()
        })
      },
      // 清空排序
      clearSort() {
        this.sortInfo = {}
        this.$refs.grid.clearSort()
      },
      // 清空表格
      emptyGrid() {
        this.loadList([])
        if (this.pageOpt) this.pageOpt.total = 0
      },
      // 手动选择多个数据，rows为已选数据数组
      selectRows(rows) {
        let arr = rows.map((item) => {
          return {
            row: item,
            selected: true
          }
        })
        this.$refs.grid.toggleRowSelection(arr)
      },
      search(infos, clear) {
        this.fixHeight()
        this.fetch(true, clear)
        this.$emit('filter', infos)
      },
      onPageChange() {
        this.fetch()
      },
      fetch(reset, clear) {
        if (this.scrollDefault) {
          this.$refs.grid.pagingScrollTopLeft(0, 0)
        }
        let arr = []
        this.$nextTick(() => {
          if (this.onFetch) {
            this.loading = true
            let data = {
              ...this.searchInfo,
              ...this.filterInfo,
              ...this.sortInfo
            }
            if (this.pageOpt) {
              if (reset) this.pageOpt.current = 1
              data.current = this.pageOpt.current
              data.page = this.pageOpt.current
              data.rows = this.pageOpt.rows
            }
            this.onFetch(data, clear)
              .then((res) => {
                if (res) {
                  setTimeout(() => {
                    this.fixHeight()
                  }, 0)
                  if (Array.isArray(res)) {
                    this.loadList(res)
                  } else {
                    if (res.list.length == 0 && this.pageOpt.current != 1) {
                      data.page = this.pageOpt.current - 1
                      data.current = this.pageOpt.current - 1
                      this.onFetch(data, clear).then((res) => {
                        this.loadList(res.list)
                        this.pageOpt.total = Number(res.total)
                      })
                    } else {
                      this.loadList(res.list)
                      this.pageOpt.total = Number(res.total)
                    }
                  }
                  this.loading = false
                } else {
                  this.loading = false
                  this.loadList(arr)
                }
              })
              .catch((err) => {
                this.loading = false
                this.loadList(arr)
              })
          }
        })
      },
      treeExpand(item, expand = true) {
        item._tree_expand = expand
      },
      getTreeRow(row) {
        let list = this.handleTree(this.currentList)
        list.some((one) => {
          if (one._XID == row._XID) {
            row = one
            return true
          }
          return false
        })
        return row
      },
      handleTreeItem(item, expand = false) {
        let tmp = []
        let cKey = this.tree.children ?? 'children'
        let hKey = this.tree.hasChild ?? 'hasChild'
        if (item[cKey]?.length > 0 || item[hKey]) {
          if (item._tree_expand || expand) {
            tmp.push(...this.handleTree(item[cKey], item._tree_level + 1, item._XID))
          }
        } else {
          item._tree_end = true
        }
        return tmp
      },
      handleTree(list, level = 0, id = '') {
        let tmp = []
        list.forEach((item, idx) => {
          if (item._tree_level == null) {
            item._tree_level = level
            item._XID = id + '_' + idx
          }
          tmp.push(item)
          tmp.push(...this.handleTreeItem(item))
        })
        return tmp
      },
      insetTree(row) {
        let cKey = this.tree.children ?? 'children'
        if (row[cKey]?.length > 0) {
          let list = this.handleList([row], row._tree_level, row._XID)
          this.$refs.grid.insertRow(list, row)
          this.$refs.grid.remove(row)
        } else {
          let data = {
            ...this.searchInfo,
            ...this.filterInfo
          }
          if (this.pageOpt) {
            data.current = this.pageOpt.current
            data.page = this.pageOpt.current
            data.rows = this.pageOpt.rows
          }
          row._tree_loading(true)
          this.tree.loadMethod(row, data).then((res) => {
            row._tree_loading(false)
            if (res.length > 0) {
              this.getTreeRow(row)[cKey] = res
              row[cKey] = res
              this.insetTree(row)
            }
          })
        }
      },
      removeTree(row) {
        let list = this.handleTreeItem(row, true)
        let arr = []
        let tmp = this.$refs.grid.getRecordset()
        tmp.forEach((item) => {
          if (list.some((one) => item._XID == one._XID)) {
            arr.push(item)
          }
        })
        this.$refs.grid.remove([...list, ...arr])
      },
      handleList(list, level = 0, id = '') {
        if (this.tree) {
          list = this.handleTree(list, level, id)
        }
        return list.map((item) => {
          this.textItems.forEach((opt) => {
            let key = opt.field.replace('_txt_', '')
            let val = opt.cell.value ? opt.cell.value(item) : this.$dt.getVal(item, key)
            if (!item.hasOwnProperty(opt.field)) {
              if (this.tree) {
                item[opt.field] = textMgr.handle(opt.cell.text, val)
              } else {
                Object.defineProperty(item, opt.field, {
                  get: () => textMgr.handle(opt.cell.text, val)
                })
              }
            }
          })
          return item
        })
      },
      loadList(list) {
        console.log(list)
        this.currentList = list
        this.$refs.grid.loadData(this.handleList(list))
      },
      onScroll(e) {
        this.$refs.head?.pagingScrollTopLeft(e.scrollTop, e.scrollLeft)
      }
    },
    mounted() {
      setTimeout(() => {
        this.fixHeight()
      }, 0)

      // 区别水印的重置方法
      window.addEventListener(
        'resize',
        () => {
          this.fixHeight()
        },
        false
      )

      this.handleIview()
      this.handleOption()

      if (typeof this.page == 'object') {
        this.pageOpt = { ...this.defaultPage, ...this.page }
      } else if (this.page) {
        this.pageOpt = this.defaultPage
      }
    }
  }
</script>

<style lang="scss" scoped>
  ::v-deep .elx-table .elx-body--column.col--ellipsis > .elx-cell {
    max-height: fit-content;
  }

  ::v-deep .ivu-tooltip-rel {
    display: inline-grid;
    position: relative;
    width: inherit;
  }
</style>
